package com.eduagent.xwqeduagent.api.SpeechEvaluation;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 语音评测服务实现类
 */
@Service
@Slf4j
public class SpeechEvaluationServiceImpl implements SpeechEvaluationService {

    @Value("${xfyun.appid}")
    private String appId;

    @Value("${xfyun.apikey}")
    private String apiKey;

    @Value("${xfyun.apisecret}")
    private String apiSecret;

    @Value("${speech.evaluation.timeout:30}")
    private int timeout; // 评测超时时间（秒）

    @Override
    public String evaluate(SpeechEvaluationParams params, byte[] audioData) throws Exception {
        if (audioData == null || audioData.length == 0) {
            throw new IllegalArgumentException("音频数据不能为空");
        }
        
        // 检查音频数据大小
        if (audioData.length > 10 * 1024 * 1024) { // 10MB限制
            throw new IllegalArgumentException("音频数据过大，超过10MB: " + audioData.length + " 字节");
        }
        
        log.info("开始评测音频数据，大小: {} 字节", audioData.length);

        SpeechEvaluationClient client = createClient();
        return doEvaluate(client, params, () -> client.sendAudio(audioData));
    }

    @Override
    public String evaluateFromFile(SpeechEvaluationParams params, String audioFilePath) throws Exception {
        if (audioFilePath == null || audioFilePath.isEmpty()) {
            throw new IllegalArgumentException("音频文件路径不能为空");
        }

        // 检查文件是否存在
        File audioFile = new File(audioFilePath);
        if (!audioFile.exists() || !audioFile.isFile()) {
            throw new IllegalArgumentException("音频文件不存在或不是有效文件: " + audioFilePath);
        }
        
        // 检查文件大小
        if (audioFile.length() == 0) {
            throw new IllegalArgumentException("音频文件为空: " + audioFilePath);
        }
        
        if (audioFile.length() > 10 * 1024 * 1024) { // 10MB限制
            throw new IllegalArgumentException("音频文件过大，超过10MB: " + audioFilePath);
        }
        
        log.info("开始评测音频文件: {}, 大小: {} 字节", audioFilePath, audioFile.length());

        SpeechEvaluationClient client = createClient();
        return doEvaluate(client, params, () -> client.sendAudioFile(audioFilePath));
    }

    /**
     * 创建评测客户端
     * @return 评测客户端
     */
    private SpeechEvaluationClient createClient() {
        if (appId == null || appId.isEmpty() || apiKey == null || apiKey.isEmpty() || apiSecret == null || apiSecret.isEmpty()) {
            throw new IllegalStateException("语音评测配置不完整，请检查xfyun.appid, xfyun.apikey, xfyun.apisecret配置");
        }
        
        return new SpeechEvaluationClient(appId, apiKey, apiSecret);
    }

    /**
     * 执行语音评测
     * @param client 客户端
     * @param params 评测参数
     * @param audioSender 音频发送器
     * @return 评测结果
     * @throws Exception 异常
     */
    private String doEvaluate(SpeechEvaluationClient client, SpeechEvaluationParams params, 
            AudioSender audioSender) throws Exception {
        
        // 检查评测文本，如果为空则使用默认文本
        if (params.getText() == null || params.getText().isEmpty()) {
            log.warn("评测文本为空，使用默认文本");
            params.setText("默认评测文本");
        }
        
        // 移除自动添加UTF8 BOM头的逻辑，因为在SpeechEvaluationClient的sendParams中处理
        log.debug("评测文本: {}", params.getText());
        
        CountDownLatch latch = new CountDownLatch(1);
        AtomicReference<String> resultRef = new AtomicReference<>();
        AtomicReference<Throwable> errorRef = new AtomicReference<>();

        // 创建监听器
        SpeechEvaluationListener listener = new SpeechEvaluationListener() {
            @Override
            public void onConnected() {
                log.info("语音评测WebSocket连接成功");
                // 连接成功后，发送音频数据的操作由外部控制
            }

            @Override
            public void onResult(String result) {
                resultRef.set(result);
                latch.countDown();
                log.info("语音评测完成，收到结果");
            }

            @Override
            public void onError(Throwable throwable) {
                errorRef.set(throwable);
                latch.countDown();
                log.error("语音评测发生错误", throwable);
            }

            @Override
            public void onClosed() {
                log.info("语音评测WebSocket连接已关闭");
                // 如果没有收到结果或错误，那么认为是异常关闭
                if (resultRef.get() == null && errorRef.get() == null) {
                    errorRef.set(new RuntimeException("WebSocket连接已关闭，但未收到评测结果"));
                    latch.countDown();
                }
            }
        };

        try {
            // 连接WebSocket服务
            log.info("正在连接语音评测服务...");
            client.connect(params, listener);
            log.info("语音评测WebSocket连接成功");

            // 发送音频数据
            try {
                log.info("开始发送音频数据...");
                audioSender.send();
                log.info("音频数据发送完成，等待评测结果...");
            } catch (Exception e) {
                log.error("发送音频数据失败: {}", e.getMessage(), e);
                throw new RuntimeException("发送音频数据失败: " + e.getMessage(), e);
            }

            // 等待评测完成或超时
            boolean completed = latch.await(timeout, TimeUnit.SECONDS);
            if (!completed) {
                throw new RuntimeException("语音评测超时（" + timeout + "秒），请检查网络连接或增加超时时间");
            }

            // 检查是否有错误
            if (errorRef.get() != null) {
                throw new RuntimeException("语音评测失败", errorRef.get());
            }

            // 返回评测结果
            String result = resultRef.get();
            if (result == null) {
                throw new RuntimeException("未收到语音评测结果");
            }
            
            return result;
        } finally {
            // 确保关闭WebSocket连接
            try {
                client.close();
                log.info("已关闭WebSocket连接");
            } catch (Exception e) {
                log.warn("关闭WebSocket连接时发生错误: {}", e.getMessage());
            }
        }
    }
    
    /**
     * 音频发送器函数式接口
     */
    @FunctionalInterface
    private interface AudioSender {
        void send() throws Exception;
    }
} 